//
// Created by wopy on 2020/8/31.
//

#include <algorithm>
#include <vector>
#include "InputState.hpp"
#include "Utils.hpp"

static string LOCAL_THESAURUS = "~/.config/bihua_thesaurus.json";
static string LOCAL_CORE = "~/.config/bihua_core.json";

using namespace std;

InputState::~InputState() {
    delete core;
    delete thesaurus;
}

InputState::InputState(FcitxInstance *owner) {
    this->owner = owner;
    this->fcitxInputState = FcitxInstanceGetInputState(owner);

    char *home = getenv("HOME");

    if (LOCAL_CORE.find("~") == 0) {
        LOCAL_CORE = LOCAL_CORE.replace(0, 1,home);
    }

    if (LOCAL_THESAURUS.find("~") == 0) {
        LOCAL_THESAURUS = LOCAL_THESAURUS.replace(0, 1,home);
    }

    if (!!!isFile(LOCAL_CORE)) {
        copyFile(DEFAULT_CORE_PATH, LOCAL_CORE);
    }
    if (!!!isFile(LOCAL_THESAURUS)) {
        copyFile(DEFAULT_THESAURUS_PATH, LOCAL_THESAURUS);
    }

    this->core = new Table(LOCAL_CORE, TABLE_TYPE_CORE);
    this->thesaurus = new Table(LOCAL_THESAURUS, TABLE_TYPE_THESAURUS);

    Table::setContext(this);
}

FcitxInstance * InputState::getInstance() {
    return owner;
}

FcitxInputState * InputState::getFcitxInputState() {
    return fcitxInputState;
}

bool InputState::hasLastInput() {
    return !!!lastInput.empty();
}

void InputState::cleanLastInput() {
    lastInput.clear();
}

void InputState::appendLastInput(const string& word) {
    lastInput += word;
}

void InputState::setMessage(const string& msg) {
    if (msg.empty()) {
        return;
    }
    FcitxInputStateSetCursorPos(fcitxInputState,
                                msg.size());   //设置消息偏移
    FcitxMessages *preedit = FcitxInputStateGetPreedit(fcitxInputState);  //获取消息组件
    FcitxMessagesSetMessageCount(preedit, 0);   //清除已有消息
    FcitxMessagesAddMessageStringsAtLast (preedit, MSG_INPUT, msg.c_str()); //显示消息
}

void InputState::getCandidateWord(FcitxCandidateWordList *dstList, const char *keyCode) {
    core->getWordListForKeyCode(keyCode, dstList, onCandWord);
}

INPUT_RETURN_VALUE InputState::getRemindCandWordList(const char *word) {
    FcitxCandidateWordList * wordList = getWordListAsZero();
    int n = thesaurus->getWordListForPrefix(word, wordList, onRemindCandWord);
    if (n > 0) {
        return IRV_DISPLAY_CANDWORDS;
    }
    return IRV_DO_NOTHING;
}

FcitxCandidateWordList * InputState::getWordListAsZero() {
    FcitxCandidateWordList *wordList = FcitxInputStateGetCandidateList(fcitxInputState);
    FcitxCandidateWordReset(wordList);
    FcitxCandidateWordSetPageSize(wordList, 5);
    FcitxCandidateWordSetChoose(wordList, DIGIT_STR_CHOOSE);
    return wordList;
}

INPUT_RETURN_VALUE InputState::onCandWord(FcitxCandidateWord *candWord) {
    char *word = strdup(candWord->strWord);
    if (hasLastInput()) {
        cleanLastInput();
    }
    upper(word);    //上屏
    core->updateFreq(word);

    if (getRemindCandWordList(word) == IRV_DISPLAY_CANDWORDS) {
        setMessage("联想");
        FcitxInputStateSetRawInputBufferSize(fcitxInputState, 0);
        FcitxInputStateGetRawInputBuffer(fcitxInputState)[0] = 0;
        return IRV_COMMIT_STRING_REMIND;
    }
    return IRV_COMMIT_STRING;
}

INPUT_RETURN_VALUE InputState::onRemindCandWord(FcitxCandidateWord *candWord) {
    char *word = candWord->strWord;
    upper(word);    //上屏
    thesaurus->updateFreq(lastInput.c_str());

    INPUT_RETURN_VALUE retVal = IRV_COMMIT_STRING;
    if (getRemindCandWordList(lastInput.c_str()) == IRV_DISPLAY_CANDWORDS) {    //还有联想词汇
        retVal = IRV_COMMIT_STRING_REMIND;
    }
    return retVal;
}

INPUT_RETURN_VALUE InputState::onCandWord(void *arg, FcitxCandidateWord *candWord) {
    InputState *state = (InputState *) arg;
    return state->onCandWord(candWord);
}

INPUT_RETURN_VALUE InputState::onRemindCandWord(void *arg, FcitxCandidateWord *candWord) {
    InputState *state = (InputState *) arg;
    return state->onRemindCandWord(candWord);
}

void InputState::upper(char *word) {
    strcpy(FcitxInputStateGetOutputString(fcitxInputState),
           word);
    appendLastInput(word);
}

bool matchKeyCode(const char *src, const char *dest) {
    int len = strlen(src);
    for (int i = 0; i < len; ++i) {
        if (dest[i] == 0)
            return false;
        if (src[i] == 'm')
            continue;
        if (src[i] != dest[i])
            return false;
    }
    return true;
}
